<?php
require_once 'pages/TMSAdminPage.inc';

class TMSListIterator extends TMSPageItemIterator {
	protected $counter;
	
	public function __construct(IIterator $base, TMSListPage $page){
		parent::__construct($base,$page);
		$this->counter = 0;
	}
	
	public function Next(){
		$this->counter++;
		return parent::Next() && (is_null($this->page->PageSize) || $this->counter <= $this->page->PageSize);
	}
	
	public function Item(){
		$item = parent::Item();
		if ($item && (is_null($this->page->PageSize) || $this->counter <= $this->page->PageSize))
			return $item;
		return null;
	}
}

class TListPageRange {
	public $LowBound;
	public $HighBound;
	public $Url;
	
	public function __construct($url,$lb,$hb){
		$this->Url = $url;
		$this->LowBound = $lb;
		$this->HighBound = $hb;	
	}
}

class TListColumn {
	private $_property_;
	public $IsShown = false;
	
	public function __construct(IPropertyMeta $property, $is_shown = false){
		$this->_property_ = $property;
		$this->IsShown = $is_shown;
	}
	
	public function Name(){
		return $this->_property_->Name();
	}
		
	public function __toString(){
		return $this->_property_->Caption();
	}
}

/**
 * @author dkrasilnikov@gmail.com
 * @property array $DisplayProperties
 * @property array $HideProperties
 * @property string $CreateLink
 * @property string $PrevPageLink
 * @property string $NextPageLink
 * @property int $Page
 * @property int $PageSize
 * @property bool $FirstPage
 * @property bool $LastPage
 * @property TMSListIterator $List
 * @property int $LowBound
 * @property int $HighBound
 * @property TListPageRange[] $PreviousRanges
 * @property TListPageRange[] $NextRanges
 * @property TListPageRange[] $Ranges 
 */

class TMSListPage extends TMSAdminPage {
	protected $list;
	
	private $_sort_by_ = array();
	private $_page_size_ = null;
	private $_page_ = null;
	private $_total_count_ = null;
	private $_search_value_ = null;
	private $_sorting_value_ = null;
	
	private $_action_urls_ = array();
	
	protected $_bool_allow_create_ = true;
	
	private $_columns_;
	
	public function __set($nm,$value){
		switch ($nm){
			case 'SortBy':$this->_sort_by_ = TConvertions::ConvertToArray($value,array(',','='),array(false,true));break;
			case 'PageSize':$this->_page_size_ = $value;break;
			case 'ActionUrls':$this->_action_urls_ = TConvertions::ConvertToArray($value,array(';','='),array(false,true));break;
			default:parent::__set($nm,$value);break;
		}
	}
	
	public function ActionUrls(IItem $item){
		$result = parent::ActionUrls($item);
		foreach ($this->_action_urls_ as $name=>$template)
			$result[$name] = $this->Service()->Url($template,null,null,array('id'=>$item->ItemId()));
		return $result;
	}	
	
	private function _fetch_list(){
		if (is_null($this->list)){
			$this->fetchList($this->request);
		}
		return $this->list;
	}
	
	private function _load_search_value(){
		if (is_null($this->_search_value_))
			$this->_search_value_ = $this->request->Cookie($this->Name().'_search');
	}
	
	private function _load_sorting_value(){
		if (is_null($this->_sorting_value_)){
			$this->_sorting_value_ = $this->request->Cookie($this->Name().'_sort');
			if ($this->_sorting_value_)
				$this->_sorting_value_ = explode(':',$this->_sorting_value_);
		}
	}
	
	protected function sortOptions(THttpRequest $request){
		$s = array();
		$this->_load_sorting_value();
		if (is_array($this->_sorting_value_)){
			$s[] = new TSortingOption($this->_sorting_value_[0],$this->_sorting_value_[1]?TSortingType::SORT_DESC:TSortingType::SORT_ASC);
		} else {
			foreach ($this->_sort_by_ as $sf=>$type){
				$t = TSortingType::SORT_ASC;
				if (defined('TSortingType::'.$type))
					$t = constant('TSortingType::'.$type);
				if (is_string($type) && !is_numeric($type))
					$t = ($type=='desc')?TSortingType::SORT_DESC:TSortingType::SORT_ASC;	
				$s[] = new TSortingOption($sf,$t);
			}
		}
		return $s;
	}
	
	protected function filterOptions(THttpRequest $request){
		$result = array();
		$this->_load_search_value();
		if ($this->_search_value_){
			$props = $this->Model->ClassProperties();
			$temp = array();
			foreach ($props as $p){
				if (($p->Type() == TItemPropertyType::PT_STRING) 
				|| ($p->Type() == TItemPropertyType::PT_MULTILINE) 
				|| ($p->Type() == TItemPropertyType::PT_HTML))
					$temp[] = new TFilterOption($p->Name(), TConditionType::C_LIKE, $this->_search_value_);
			}
			if (!empty($temp))
				$result[] = new TCondition(TConditionType::C_OR, $temp);
		}
		return $result;
	}
	
	protected function fetchList(THttpRequest $request){
		$count = null;
		$offset = null;
					
		if ($this->_page_size_){
			$offset = ($this->Page - 1)*$this->_page_size_; 
			$count = $this->_page_size_;
		}
		$this->_total_count_ = 0;
		$lo = new TListOptions($this->filterOptions($request), $this->sortOptions($request), $count, $offset);
		$this->list = new TMSListIterator($this->Model->GetList($lo,$this->_total_count_),$this);
	}
	
	public function __get($nm){
		switch ($nm){
			case 'PageSize':return $this->_page_size_;break;
			case 'Page':return $this->_page_?$this->_page_:1;break;
			case 'LowBound':return $this->_page_?(($this->_page_ - 1)*$this->_page_size_)+1:1;break;
			case 'HighBound':{$this->_fetch_list();return $this->LowBound + $this->list->ItemCount() - 1;}break;
			case 'CreateLink':return $this->_bool_allow_create_?$this->service->ItemCreateUrl($this->Model->ClassName):null;break;
			case 'PrevPageLink':return $this->Url(null,null,array('pagenum'=>$this->Page-1));break;
			case 'NextPageLink':return $this->Url(null,null,array('pagenum'=>$this->Page+1));break;
			case 'FirstPage':return $this->LowBound == 1;break;
			case 'LastPage':return $this->HighBound == $this->_total_count_;break; 
			case 'List':{$this->_fetch_list();return $this->list;}break;
			case 'SearchValue':{$this->_load_search_value();return $this->_search_value_;}break;
			case 'PreviousRanges':{
				$result = array();
				if ($this->_page_size_){
					$pn = 1;
					$offset = 1;
					while ($offset < $this->LowBound){
						$result[] = new TListPageRange($this->Url(null,null,array('pagenum'=>$pn)), $offset, $offset + $this->_page_size_ - 1);  
						$offset += $this->_page_size_;
						$pn++;
					}
				}
				return $result;
			}break;
			case 'NextRanges':{
				$result = array();
				if ($this->_page_size_){
					$pn = $this->_page_ + 1;
					$offset = $this->HighBound + 1;
					while ($offset <= $this->_total_count_){
						$result[] = new TListPageRange($this->Url(null,null,array('pagenum'=>$pn)), $offset, $offset + (($this->_total_count_ - $offset < $this->_page_size_)?($this->_total_count_ - $offset):$this->_page_size_));  
						$offset += $this->_page_size_;
						$pn++;
					}
				}
				return $result;
			}break;
			case 'Ranges':{
				return array_merge($this->PreviousRanges,$this->NextRanges);
			}break;
			case 'AvailableColumns':{
				if (is_null($this->_columns_)){
					$this->_columns_ = array();
					foreach ($this->Model->ClassProperties() as $p)
						$this->_columns_[] = new TListColumn($p,empty($this->displayProperties) || in_array($p->Name(), $this->displayProperties));
				}
				return $this->_columns_;
			}break;			
			default:return parent::__get($nm);break;
		}
	}
	
	public function http_SetSearchValue($criteria){
		$this->SetCookie($this->Name().'_search', $criteria);
		$this->_search_value_ = $criteria;
	}
	
	public function SortingUrl($property){
		return $this->Url(null,'ToggleSorting',array('property'=>$property));
	}
	
	public function SortingProperty(){
		$this->_load_sorting_value();
		if (is_array($this->_sorting_value_)){
			return $this->_sorting_value_[0];
		}
		return null;
	}
	
	public function SortingOrder(){
		$this->_load_sorting_value();
		if (is_array($this->_sorting_value_))
			return $this->_sorting_value_[1]?TSortingType::SORT_DESC:TSortingType::SORT_ASC;
		return null;
	}
	
	public function http_ToggleSorting($property){
		$this->_load_sorting_value();
		if (is_array($this->_sorting_value_) && ($this->_sorting_value_[0] == $property)){
			$this->_sorting_value_[1] = $this->_sorting_value_[1]?0:1;
		} else $this->_sorting_value_ = array($property,0);
		$this->SetCookie($this->Name().'_sort', join(':', $this->_sorting_value_));
		$this->Application()->Redirect($this->Url());
	}
		
	public function Handle(THttpRequest $request){
		if ($request->pagenum){
			$this->_page_ = $request->pagenum;
			$this->SetCookie($this->Name().'_pn', $this->_page_);
			unset($request->pagenum);
		} 
		parent::Handle($request);
	}
}